import _ from 'lodash';

import { logPublicRequest, firewallRequest } from '@core/utils/request';
import Session from '@core/engine/Session';
import * as Enums from './Enums';
import { PaginationResponse } from './Base';
import SecPolicy from './SecPolicy';

export default class LogService {
  static fetchRawLogs = (params: FetchRawLogParams) => {
    const { userid, loggroup, logunit, page, size, keys, ...otherParams } = params;
    const searchHeaders = {
      userid, loggroup, logunit, page, size,
    };
    // 若 key 或 value 为空值，或者在精确匹配时值为 all，则不传这一条查询条件
    const nonEmptyKeys = keys.filter((keyRow) => !!keyRow.key && !!keyRow.value)
      .filter((keyRow) => !(keyRow.judge_mode === Enums.LogJudgeMode.Equal && keyRow.value === Enums.FILTER_ALL));
    return logPublicRequest.post<
      FetchRawLogParams,
      FetchRawLogsResponse
    >(
      '/ctcloud/ctyun/getRawLog',
      { keys: nonEmptyKeys, ...otherParams },
      { headers: searchHeaders },
    );
  };

  static fetchSetting = (params: { firewallId: string }) => {
    return firewallRequest.get<
      { firewallId: string },
      LogSetting
    >('/ctcloud/vfw/v1_log_setting_info', { params: { ...params, uid: Session.getAccountId() } });
  };

  static fetchOperationLogs = (params: OperationLogParams) => {
    return firewallRequest.get<
      OperationLogParams,
      PaginationResponse<OperationLog>
    >('/ctcloud/vfw/v1_operation_log_query', { params: { ...params, uid: Session.getAccountId() } });
  };

  static fetchRuleNameOfLogs = async (logs: Array<RawLog>, firewallId?: string) => {
    if (!firewallId) {
      return;
    }
    const fetchRulePromises: Array<Promise<void>> = [];
    const ruleIds = logs.map((log) => log.rule_id).filter((ruleId) => !!ruleId);
    _.uniq(ruleIds).forEach((ruleId) => {
      fetchRulePromises.push(LogService.updateLogsRuleName(logs, firewallId, ruleId));
    });
    await Promise.all(fetchRulePromises);
  };

  private static updateLogsRuleName = async (logs: Array<RawLog>, firewallId: string, ruleId: string) => {
    const secPolicy = await SecPolicy.fetchOne({ firewallId, ruleId });
    logs.filter((log) => log.rule_id === ruleId).forEach((log) => { log.rule_name = secPolicy?.ruleName; });
  };
}

interface LogServiceResponse {
  result_code: number,
  reason: string,
}

interface LogServicePaginationResponse extends LogServiceResponse {
  page: number,
  page_count: number,
  size: number,
  total: number,
}

interface FetchRawLogKeywordPair {
  key: string,
  value?: string,
  value1?: string,
  judge_mode: number,
}

export interface FetchRawLogParams {
  userid: string,
  loggroup: string,
  logunit: string,
  page: number,
  size: number,
  start_time: string,
  end_time: string,
  is_full_index: number,
  keyword?: string,
  judge_mode: number,
  keys: Array<FetchRawLogKeywordPair>,
}

export interface RawLog extends Record<string, string> {
  raw_log: string,
}

export interface FetchRawLogsResponse extends LogServicePaginationResponse {
  raw_logs: Array<RawLog>,
}

export interface LogSetting {
  auditAttackId: string,
  auditAttackName: string,
  auditEventId: string,
  auditEventName: string,
  auditFlowId: string,
  auditFlowName: string,
  auditGroupId: string,
  auditGroupNameId: string,
  firewallId: string,
  logUserId: string,
  osId: string,
  uid: string
}

export interface OperationLog {
  action: string,
  content: string,
  firewallId: string,
  osId: string,
  firewallName: string,
  severities: string,
  uid: string,
}

export interface OperationLogParams {
  firewallId: string,
  severities?: string,
  action?: string,
  content?: string,
  beginTime: number,
  endTime: number,
  page: number,
  size: number,
}
